package cloud.coder.remote.grpc.client.service;

import cloud.coder.remote.boot.BootService;
import cloud.coder.remote.boot.DefaultImplementor;
import cloud.coder.remote.boot.ServiceManager;
import cloud.coder.remote.grpc.client.GRPCChannelListener;
import cloud.coder.remote.grpc.client.GRPCChannelManager;
import cloud.coder.remote.grpc.client.GRPCChannelStatus;
import io.grpc.Channel;
import io.grpc.StatusRuntimeException;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

@DefaultImplementor
public class HelloServiceClient implements BootService, GRPCChannelListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(HelloServiceClient.class);

    private volatile GRPCChannelStatus status = GRPCChannelStatus.DISCONNECT;
    private volatile GreeterGrpc.GreeterBlockingStub serviceBlockingStub;

    @Override
    public void prepare() {
        ServiceManager.INSTANCE.findService(GRPCChannelManager.class).addChannelListener(this);
    }

    @Override
    public void boot() {

    }

    @Override
    public void onComplete() {

    }

    @Override
    public void shutdown() {

    }

    public void greet(String name) throws InterruptedException {
        LOGGER.info("Will try to greet " + name + " ...");
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloReply response;
        if (status != GRPCChannelStatus.CONNECTED) {
            TimeUnit.SECONDS.sleep(1);
        }
        try {
            response = serviceBlockingStub.sayHello(request);
        } catch (StatusRuntimeException e) {
            LOGGER.warn("RPC failed: {0}", e.getStatus());
            LOGGER.error(e.getMessage(), e);
            return;
        }
        LOGGER.info("Greeting: " + response.getMessage());
    }


    @Override
    public void statusChanged(GRPCChannelStatus status) {
        if (GRPCChannelStatus.CONNECTED.equals(status)) {
            Channel channel = ServiceManager.INSTANCE.findService(GRPCChannelManager.class).getChannel();
            serviceBlockingStub = GreeterGrpc.newBlockingStub(channel);
        }
        this.status = status;
    }
}
